home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Original Shareware 1.1
/
The Original Shareware (WeMake CDs)(Volume 1.1)(CDs, Inc)(1993).iso
/
5
/
olaf.zip
/
OLAF.DOC
next >
Wrap
Text File
|
1986-01-12
|
63KB
|
1,416 lines
(tm)
OLAF
Copyright(c) 1986
by
A. D. Clark
2119 Ridge Avenue
Evanston, IL 60201
U.S.A.
Version 1.0
I. Introduction
OLAF stands for "On Line Access of Files". It is a data base
management program developed especially for transaction processing
applications on personal computers. Transaction process is defined to
be the set of data processing applications in which transaction records
of one file are used to make changes to the records of one or more
other files. In addition to its transaction processing features, OLAF
has powerful inquiry and reporting features.
OLAF is executed using its own command language. With a few of its
brief commands it can do things which it would take entire programs to
do in languages like COBOL and C. Its interactive mode makes it easy
to learn and use.
II. OLAF Cribsheet
The cribsheet is meant to be printed and referred to as an aid in
using OLAF.
Commands Options Special Characters
-------- ------- ------------------
Add Silence // Carriage Return
Build To [] Blank
Change Find "" Quote
Constant Nocarriage <- Backspace
Declare Repeat | Tab
Delete Noise = Assignment
End Nowrite /* .. */ Comment Delimiters
Execute Page ( .. ) Expression Delimiters
Fields { .. } Statement Delimiters
File & Line Continuation Symbol
Final Modifiers ^ .. ^ Modifier Delimiters
Heading ---------
Let n.d
New Descending
Open Variable
Print Code
Proc Comma
Redefine DDMMMYYYY Arithmetic Operators
Reset MM/DD/YY --------------------
Select + Addition
Sort - Subtraction
Title * Multiplication
/ Division
Relational Operators ** Exponentiation
-------------------- ^/ Square Root
= Equality
!= Inequality Statment Commands
> Greater Than -----------------
< Less Than IF condition THEN statement
<= Less Than, Equal To ELSE statement
>= Greater Than, Equal WHILE condition DO statement
CALL procedure
TTY field-name
Alpha Arithmetic
---------------- Compound Condition Conjunctions
+ Concatenation -------------------------------
* Propogation AND
OR
Date Arithmetic
---------------
+ Addition
- Subtraction
File Byte
Field Types Size Range
----------- ---- -----
Short 1 0 through +255
Int 2 -32,768 through +32,767
Unsigned 2 0 through 65,535
Long 4 -2,147,483,648 - +2,147,483,647
Float 4 Large numbers, no decimals.
Double 8 Large numbers, decimals allowed.
Coded 1 0 through +255
Date 4 Year 0 through +5,772,805
Alpha Equal to the
specified
number of
characters.
Temporary Variables
Field Types
-----------
Long Sizes and ranges for temporary variables are
Double the same as for file fields.
Alpha
Date
File Definition Options
-----------------------
Minimum
Maximum
Decimals <number of decimals in I-O for a double>
Code <size /g the code name for a coded field>
Mult <number of list entries for a coded field>
Pname <size of the print name for a coded field>
II. Command Syntax Summary
The underscores indicate the parts of the command element that are
required. The square brackets where they are not underscored indicate
optional command elements
A. Main Level Commands
-------------------
Any of the following commands are valid after the "*" prompt.
ADD
-
BUILD [/<options>/] <filename>
- - -
CHANGE [/<options>/] IF <condition> THEN { <statement> } [ELSE] <statement>, ...
- - - -- ----------- ---- - -
CONSTANT <varname> = <value>, ...
-- --------- - -------
DECLARE <variable type> <varname> [[<dimension>]] = <value>, ...
- -------------- --------- - -
DECLARE ALPHA <varname> [<<field size>>] [[<dimension>]] = <value>, ...
- - - - - -
DELETE [/<options>/] [IF] <condition>
--- - - -----------
END
-
EXECUTE [/<options>/] <filename>
-- - - ----------
FIELDS [/<options>/]
- - -
FILE <file reference number>
--- -----------------------
FINAL <statement>, ...
---
HEADING <statement>, ...
-
LET <statement>, ...
-
NEW <filename>
- ----------
OPEN <filename>, ...
- ----------
PRINT [/<options>/] <statement>, ...
- - -
PROC <procedure name> <file reference number>
--- ---------------- -----------------------
REDEFINE
---
RESET
-
SELECT [/<options>/] [IF] <condition>
- - - -----------
SORT [/<options>/] <statement>, ...
-- - -
TITLE <statement>, ...
-
B. Redefinition Level Commands
---------------------------
Any of the following commands are valid after the ">>" prompt.
ADD CODE <field name> "<code name>" = "<print name>"
- - ------------ ------------- - --------------
ADD FIELDS
- -
ADD NAME <existing field name> <new field name>
- - --------------------- ----------------
CHANGE CODE <field name> "<code or print name>" [=] "<code or print name>"
-- - ----------- ---------------------- ----------------------
CHANGE MAXIMUM <field name> <number or date>
-- -- ------------ ----------------
CHANGE MINIMUM <field name> <number or date>
-- - ------------ ----------------
CHANGE MULT <coded field name> <number>
-- -- ------------------ --------
CHANGE NAME <existing field name> <new field name>
-- - --------------------- ----------------
FIELDS
-
IV. Examples
A. Labels and Phone Lists
----------------------
Features and topics covered:
File Definition
Coded Fields
Adding Data
Changing Data
Selection
Printing
Sorting
Rebuilding
Redefinition
The first thing that one needs to know how to do in any database
management system is the definition of the file. Our first example a
simple phone list and label system. Our file will store individuals'
name, address, city, state, zip code, and phone number.
*NEW NAME.OLF
Enter #fields, #records 8,100
Field #1 ALPHA15,LAST_NAME:LN
Field #2 ALPHA15,FIRST_NAME:FN
Field #3 ALPHA30,ADDRESS:ADDR:A
Field #4 ALPHA20,CITY:CIT:C
Field #5 CODE "AL"="ALABAMA" "CA"="CALIFORNIA" &
.. "IL"="ILLINOIS" "WI"="WISCONSIN",STATE:ST:S
Field #6 ALPHA5,ZIP:Z
Field #7 UNSIGNED,AREA_CODE:AC
Field #8 LONG,PHONE_NUMBER:PHONE:PN
File Defined
*
el+ZY first field of the record is the individual's last name. A field
name must begin with a letter, and can contains numbers and the
underscore character or a period. The maximum space this file allows
for last names is fifteen alphanumeric characters. There is a single
synonym defined for last name. It is the abbreviation "LN". The next
three fields, first name, address, and city are variations on the
alphanumeric theme.
Following city comes a coded field. A coded field allows input of
alphanumeric character strings from a predefined list. Input can be in
short or long form. In the example, Alabama may be entered as "AL" or
as "ALABAMA". The use of coded fields is appropriate where the
possible inputs are obvious. For example, the states of the United
States, the countries of the world, the products of a company, or the
colors of fabrics, are all things from lists which can be predefined.
Even if the list is subject to change the use of coded fields is
recommended because of the advantages. One advantage is a significant
reduction in file size. Smaller field size and file size results in
more efficiency when OLAF needs to do a selection. Another advantage
is the improvement of input, since only specific entries are possible.
The last advantage cited here is that records can be summoned up in a
selection using abbreviation, saving keystrokes. Other advantages will
be evident later.
Following the coded field comes a five character field for the zip
code, and following it comes the first completely numeric field for the
area code. The unsigned numeric allows positive number ranging from 0
through 65,235. Finally, there is a long numeric field for the phone
number.
Records can be added to a file interactively using the ADD command.
Type ADD and tap the carriage return key to start it.
*add
LAST_NAME Levie
FIRST_NAME Jack
ADDRESS 230 West Monroe
CITY Chicago
STATE IL
ZIP 60690
AREA_CODE 312
PHONE_NUMBER 7822000
1 Record Added
*
The same record could be entered somewhat less interactively using the
BUILD command. Type BUILD and tap return to get it started.
*build
"Levie" "Jack" "230 W. Monroe" "Chicago" "IL" "60650" 312 7822000
ESC
1 Record Built
*
The ESC symbol means the escape key. Control-Y or Control-Z are
substitutes. Any one of the three indicates end of file to OLAF.
Entering records with the BUILD command may be slightly faster than
using the ADD command, however it demands greater typing accuracy.
Note that many records at a time may be entered with the BUILD command.
*build
"Levie" "Jack" "230 W. Monroe" "Chicago" "IL" "60650" 312 7822000
"Kornbluh" "M." "230 Monroe" "Chicago" "IL" "60650" 312 7822000
"Fabry" "M." "230 Monroe" "Chicago" "IL" "60650" 312 7822000
ESC
2 Records Built
*
The third style of record entry is to use an editor to create an ASCII
file, then use the BUILD command to add the records to the OLAF file.
The format of the records within the ASCII file should follow the
format of the above example of the interactive BUILD command.
*build data.tmp
30 Records Built
*
There are three styles of the CHANGE command to fix records. The first
is the mass change.
*CHANGE IF ADDR = "230 Monroe" THEN {ADDR = "230 West Monroe"}
2 Records Changed
*
Every record that matches the condition to the left of THEN will
undergo the change defined within the brackets.
The second style is the mass-interactive CHANGE.
*CHANGE IF FN = "M." THEN {LN; FN = TTY FN}
Kornbluh
FIRST_NAME Marty
Fabry
FIRST_NAME Mike
2 Records Changed
*
The mass-interactive CHANGE allows a different assignment of some new
values for every record that satifies the condition to the left of
THEN.
The interactive CHANGE is the third style. In it, both the left and
right sides of the command accept variable input.
*CHA/REPEAT, FIND 1/IF LN = TTY LN THEN {ADDR; ZIP; &
... ADDR = TTY ADDR; ZIP = TTY ZIP}
LAST_NAME Fabry
230 West Monroe 60690 ADDRESS 230 Monroe
ZIP 60606
1 Records Changed
LAST_NAME Kornbluh ADDRESS 230 Monroe
230 West Monroe 60690
ZIP 60606
1 Records Changed
LAST_NAME ESC
0 Records Changed
*
The escape character is again the means to tell OLAF to end the
session, as it was in the BUILD command. Note the options appearing
within the slashes. REPEAT is the way to make the command execute any
number of times. In this example, the FIND option tells OLAF to select
only one record as a candidate for change.
Reporting in OLAF is broken into three primary parts, which are
selecting, sorting, and printing. Selecting is the part that retrieves
the records to be printed.
*select if area_code = 312
3 Records Selected
*
The select list remains unchanged until another SELECT command is
given, or another command is given that can alter the select list.
Such commands are CHANGE and BULD. ADD does not completely alter the
select list, but it appends to it. SORT alters the order but not the
contents of the select list.
*sort last_name; first_name ;
Sorting 3 Records. Key is 32 bytes. 1 partitions.
*
The sorted list awaits another PRINT command to show the results of its
work.
*print ln; fn;
Fabry Mike
Kornbluh Marty
Levie Jack
*
The select list remains sorted until another SORT command changes its
order. A SORT command can be issued without any key references. The
effect of the keyless sort is to return the select list back to its
original state.
The following PRINT command shows how to print labels. It makes liberal
use of abbreviations and a few special symbols. Semicolons delineate
statements. The circumflexes delineate print modifiers, and the "v"
within the circumflexes is an abbreviation of "variable", which is a
commonly used modifier in OLAF. The double slash is the
carriage-return-line-feed symbol. The backarrow is the backspace.
*p ln^v^; <-; ","; fn; //; addr; //; city^v^; <-; ","; st^v^; &
.. zip; 3 * //
Fabry, Mike
230 W. Monroe
Schaumburg, ILLINOIS 60606
Kornbluh, Marty
230 Monroe
Chicago, ILLINOIS 60606
Levie, Jack
230 W. Monroe
Chicago, ILLINOIS 60690
*
It might be imagined that for some reason the writer of the report
decides that it is unsatisfactory to have the state in upper case
characters. What can be done? The CHANGE command can't solve the
problem because the state field is coded. One way to solve the
problem, using command already explained, is to rebuild the file. The
following commands begin the job.
*s 1=1
3 Records Selected
*p/to dat.tmp/ ""+ln+""; ""+fn+""; ""+a+""; ""+c+""; &
.. ""; <-; s^code^; <-; ""; ""+z+""; ac; pn
*f/to name.def/
The first of the three above commands may seem peculiar. In English it
says "select if one equals one", which is a condition that is always
true. This is a command that selects every record of a file regardless
of the values of the fields of the file.
The above print command shows the option for printing to devices and
files. Note that the same option may be used to direct the output to a
printer (it would be "to prn:").
An intermediate step in file rebuilding that can not be done within
OLAF is to use an editor to change the OLAF definition file created by
the FIELDS command in the last of the above three steps. After
editing, the file might look like the following.
new NAME.OLF
8,100
ALPHA15,LAST_NAME:LN
ALPHA15,FIRST_NAME:FN
ALPHA30,ADDRESS:ADDR:A
ALPHA20,CITY:CIT:C
CODE/MULT 60 CODE 2 PNAME 20/ "AL"="Alabama" "CA"="California" &
"IN" = "Indiana" "IL"="Illinois" "WI"="Wisconsin",STATE:ST:S
ALPHA5,ZIP:Z
UNSIGNED/MIN 0 MAX 65535/,AREA_CODE:AC
LONG/MIN 0 MAX 0/,PHONE_NUMBER:PHONE:PN
Note that Indiana is a new entry in the list of states. Redefinition
and rebuilding are the way to add to the coded lists. The above file
definition shows some important definition options. The option MULT
defines the maximum number of entries that can be in the coded list.
This can be increased to a maximum of 255. CODE 2 specifies that the
size of the code value, that which is to the left of the equal signs in
the list of entries, is two characters. PNAME 20 means that the values
to the right of the equal signs may be as large as twenty characters.
Both the CODE and PNAME parameters may be adjusted as desired.
Rebuilding is completed by the following two steps.
*ex name.def
Enter #fields, #records
Field #1
Field #2
Field #3
Field #4
Field #5
Field #6
Field #7
Field #8
File Defined
*build dat.tmp
3 Records Built
*
In the above rebuilding example only the coded list was changed. If it
were necessary to add fields to the record, increase the size of the
file, or alter the definition of a field, rebuilding could be the
solution. However, there is another set of commands which permit the
redefinition of coded fields in a more convenient way.
*redefine
>>change code state "ILLINOIS" = "Illinois"
>>change code state "ALABAMA" = "Alabama"
>>add code state "In" = "Indiana"
>>change code state "In" = "IN"
>>end
*
Some other redefinition of files short of complete rebuilding is
possible. Fields can be added using the "ADD FIELDS" command, minima
and maxima can be changed, synonyms can be added for field names, field
names can be changed, and the "MULT" value of a coded field can be,
within limits, changed. The limit is that the sum of the "code" and
"pname" sizes times the new "MULT" and divided by 512 must yield a
quotient that is the same as the quotient given by the old "MULT",
keeping the other values the same. Redefinition can not change field
types, field sizes, and file sizes. Nor can redefinition delete
fields. Use rebuilding to solve such problems.
To resume the introduction to the PRINT command, here is an example of
a phone list.
*s 1=1
3 Records Selected
*p ln + ", " + fn; 50 * "."; |50; ac^v^; <-; "-"; pn^v^
Fabry, Mike ......................................312-7822000
Levie, Jack ......................................312-7822000
Kornbluh, Marty ..................................312-7822000
*
The phone list program shows concatenation of the last name, a comma, a
space, and the first name. It shows an example of propogation of a
singe character. It has a tab to column 50. It also uses the variable
modifier in conjunction with two numeric fields.
B. Statistics and a Histogram
--------------------------
Features and topics covered:
Arithmetic
Final
Heading
IF
Modifiers
Reset
Storing Programs
Summary Reporting
TTY Graphics
WHILE
The OLAF programs in this section use a file which has a field named
grade with a synonym of "g". The range of possible scores is from zero
through one hundred.
The first program is an example of summary reporting. The objective is
to calculate the mean of all the grades. It is not important to see
the details. Therefore, the PRINT command's purpose is not to show
items but to sum the grades and the number of items in the set. The
PRINT command uses the NOCARRIAGE option, which suppresses the carriage
control that normally follows the detail line of print. The FINAL
command is an auxiliary print command. OLAF executes the FINAL after
the last print detail line. It is a good habit to use the RESET
command. Its purpose is to free space for temporary variables. It
erases OLAF's memory of temporary variables, auxiliary print commands,
and procedures.
*reset
*dec i count ;
*dec d sum, avg, var, varsq, sumvar;
*final avg = sum/count; "Count = "; count ; &
.. "Sum ="; sum^7.2^; "Avg = "; avg^7.2^ ;
*s 1=1
46 Records Selected
*print/noc/sum = sum + g; count = count + 1;
Count = 46 Sum = 3651.00 Avg = 79.37
The next example uses another auxiliary print command: the HEADING. A
HEADING executes before the first detail line and at regular intervals
as determined by the PAGE option of the PRINT command. In the FINAL
command following the variable "sumvar" there are two new print
modifiers. The "variable" modifier directs OLAF to leave as much space
as needed for the number and no more, and the "comma" modifier puts
commas into numbers at the proper places.
*final "Total Variance ="; sumvar^15.2 var comma^; &
.. "Standard Deviation ="; &
.. ^/(sumvar/(count - 1))^7.2^ ;
*heading "Count"; |15; "Difference"; |30; "Diff. Squared"; //; &
.. "-----"; |15; "----------"; |30; "-------------"
*print g; if g > avg then var = g - avg; else var = avg - g; &
.. |15 ; var^10.2^ ; |30 ; varsq = var ** 2 ; &
.. varsq^13.2^ ; &
.. sumvar = sumvar + varsq ;
Count Difference Diff. Squared
----- ---------- -------------
78 1.37 1.88
80 0.63 0.40
85 5.63 31.70
. . .
. . .
. . .
88 8.63 74.48
86 6.63 43.96
88 8.63 74.48
Total Variance = 2,690.72 Standard Deviation = 7.73
The final example of this section begins with a HEADING command that
stands alone. OLAF remembers auxiliary print commands from PRINT to
PRINT command. Entering HEADING by itself makes OLAF discard a
previously entered HEADING. OLAF provides a feature called "string
arithmetic". The example shows that it is permissible to "multiply" a
literal and an integer value. The effect is a propogation of the
literal. The example shows that this feature makes it simple to write
a histogram with OLAF.
*heading
*dec i count[20], i ;
final i = 0; while i <= 20 do { i * 5;count[i]; &
.. count[i] * "XX"; //; i = i + 1 };
print/noc/ i = g/5; count[i] = count[i] + 1 ;
0 0
5 0
10 0
15 0
20 0
25 0
30 0
35 0
40 0
45 0
50 0
55 1 XX
60 0
65 3 XXXXXX
70 6 XXXXXXXXXXXX
75 12 XXXXXXXXXXXXXXXXXXXXXXXX
80 8 XXXXXXXXXXXXXXXX
85 12 XXXXXXXXXXXXXXXXXXXXXXXX
90 4 XXXXXXXX
95 0
100 0
OLAF command sequence can be stored in files using an editor. The
EXECUTE command retrieves a file containing command sequences and
follows its directions. Debugging a program is made easier using the
"noise" option with the EXECUTE command. OLAF shows the files
instructions as it attempts to compile and execute them. OLAF points
to problems and gives error messages.
*ex program.src
C. Transaction Processing
----------------------
Features and topics covered:
Sorting Alternatives
Multiple Files
Transaction Processing
The example to be examined to introduce the application of transaction
processing in OLAF is a basic order entry system. The particular
system is imagined to be for a furniture retailer who keeps an
inventory of fewer than 256 basic items. The retailer can therefore
use a coded field to describe the basic items he sells. A basic item
can have a variety of colors and textures. A second coded field
describes the inventory item in more detail. An unsigned integer is
believed to be more than sufficient for the purpose of numbering the
customers. This particular retailer gets most of his business from
fewer than 200 repeat business customers. He can't imagine ever having
65,000 customers. But if he someday decides to sell more aggressively
directly to the public, a possible way of adjusting the system for the
new environment would be to change the customer number from an unsigned
field to a long field. The files would, of course, need to be
redefined and rebuilt.
The remaining fields of the order file concern the quantities and the
significant dates occuring in the life of an order item. The order
date has a minimum value corresponding to the system's inception. The
shipping date, shipped quantity, and billing date are all unknown at
the time the order is entered, and are entered as zeroes. These fields
are updated in the course of transaction processing.
Every three months there will be some special processing. The order
file is large enough to hold 15,000 order line items, which is 50% more
than the order line items this business has ever had in a quarter. At
the end of every three months, a new order file will be defined. The
unfilled orders shall be extracted from the old order file and built
into the new file. This is done using the rebuilding procedure
outlined in the above section on labels and phone lists.
ORDER.OLF
8,15000
UNSIGNED/MIN 0 MAX 65535/,CUSTOMER:CUST:C
CODE/MULT 50 CODE 3 PNAME 30/ "AC"="ARM CHAIR" &
"AQ"="AQUARIUM STAND" "BBD"="BUTCHER BLOCK DESK" &
"BBT"="BUTCHER BLOCK TABLE" "BSH"="HIGH BOOK SHELVES" &
"BSL"="LOW BOOK SHELVES" "BWC"="BENT WOOD CHAIR" &
"CA"="CARPET" "CAF"="CAFETERIA TABLE" "CH"="CHAIR" &
"CHN"="CHANDELIER" "CON"="CONFERENCE TABLE" "CT"= &
"COFFEE TABLE" "CR"="CREDENZA" "CU"="CUBICAL TABLE" &
"DE"="DESK" "DES"="SECRETARY'S DESK" "DIR"="DIRECTOR'S CHAIR" &
"ED"="EXECUTIVE DESK" "FC"="FOLDING CHAIRS" "FL"= &
"FLOOR LAMP" "GLO"="GLOBE" "HIL"="HIGH INTENSITY LAMP" &
"LS"="LAMP STAND" "LSH"="LAMP SHADE" "MTD"="MARBLE TOPPED DESK" &
"MPH"="MARBLE PEN HOLDER" "PCA"="PADDED CHAIR WITH ARMS" &
"PCN"="PADDED CHAIR, NO ARMS" "PSC"="PARTITION CORNER SECITON" &
"PS4"="PARTITION SECTION: 4' x 4'" "PS8"="PARTITION SECTION: 8' x 4'" &
"PSD"="PARTITION CLOSET DOOR" "PSH"="PARTITION SHELVING" &
"RC"="RECLINING CHAIR" "RL"="READING LAMP" "SC"= &
"SWIVEL CHAIR" "SCR"="AUDIO-VISUAL SCREEN" "SO"= &
"SOFA" "TA"="TABLE" "TG"="GLASS TABLE" "TL"="TABLE LAMP" &
"TO"="OVAL TABLE" "TR"="ROUND TABLE" "TT"="TYPING TABLE",PRODUCT &
:PROD:P
CODE/MULT 60 CODE 3 PNAME 20/ " "=" " "BE"="BEIGE" "BLK"= &
"BLACK" "BLL"="LIGHT BLUE" "BLS"="BLACK STEEL" "BLU"="BLUE" &
"BP"="BLACK PLASTIC" "BR"="BROWN" "BRD"="LIGHT BROWN" "BRL"= &
"LIGHT BROWN" "BU"="BURGUNDY" "CAN"="CANVAS" "DA"="DARK" &
"DR"="DARK RED" "FAL"="LIGHT FABRIC" "FAD"="DARK FABRIC" &
"FW"="WHITE FABRIC" "FB"="BLACK FORMICA" "GR"="GREY" "GRD"= &
"DARK GREY" "GRL"="LIGHT GREY" "GRN"="GREEN" "GL"="LIGHT GREEN" &
"HI"="HIGH" "KH"="KHAKI" "LI"="LIGHT" "LV"="LIGNUM VITAE" &
"LO"="LOW" "MA"="MAPLE" "MAB"="BIRD'S EYE MAPLE" "MAU"= &
"MAUVE" "MH"="MAHOGANY" "OA"="OAK" "ORA"="ORANGE" "OR"= &
"ORIENTAL" "PE"="PERSIAN" "PI"="PINK" "PIN"="PINE" "PDS"= &
"DARK STAINED PINE" "PLS"="LIGHT STAINED PINE" "RE"="RED" &
"SP"="SPRUCE" "ST"="STEEL" "TK"="TEAK" "TKS"="STAINED TEAK" &
"WA"="WALNUT" "WAD"="DARK WALNUT" "WAL"="LIGHT WALNUT" &
"WF"="WHITE FORMICA" "WH"="WHITE" "WO"="WOOD" "YE"="YELLOW" &
"YEC"="CANARY YELLOW" "YP"="YELLOW PLASTIC",COLOR:COL:CO
SHORT/MIN 0 MAX 255/,QUANTITY:QUANT:Q
DATE/MIN 8OCT1985 MAX 8OCT1989/,ORDER_DATE:OD:O
DATE,SHIP_DATE:SD:S
DATE,BILL_DATE:BD:B
SHORT/MIN 0 MAX 255/,QUANTITY_SHIPPED:QS
The inventory file is large enough to contain 1,500 items. For each
combination of product and color there should be exactly one record in
the inventory file. When the retailer starts to carry a new
combination of product and color, he ADDs a record to the inventory
file. When he buys more of an item from the manufacturers or
wholesalers, he CHANGEs the record in the inventory file for the item,
increasing the quantity.
INVENT.OLF
4,1500
CODE/MULT 50 CODE 3 PNAME 30/ "AC"="ARM CHAIR" &
.
. (same codes as in the order file)
.
"TO"="OVAL TABLE" "TR"="ROUND TABLE" "TT"="TYPING TABLE",PRODUCT &
:PROD:P
CODE/MULT 60 CODE 3 PNAME 20/ " "=" " "BE"="BEIGE" "BLK"= &
.
. (same codes as in the order file)
.
"YEC"="CANARY YELLOW" "YP"="YELLOW PLASTIC",COLOR:COL:CO
UNSIGNED/MIN 0 MAX 65535/,QUANTITY:QUANT:Q
DOUBLE/DEC 2 MIN 0 MAX 0/,PRICE:PRI:PR
How can the retailer be sure that there is only one record in the
inventory file for each combination of product and color? After ADDing
records to the inventory file, he always runs a report that checks for
duplicates.
*select if 1=1
675 Records Selected
*dec a hold_p<30>, hold_co<20> ;
*sort p;co
Sorting 675 Records. Key is 52 bytes. 3 partitions.
*p/noc/if p = hold_p and co = hold_co then {p;co;//}; &
.. hold_p = p; hold_co = co
CREDENZA OAK
The check for duplicates detects a single duplicates among the 675
records in the file. Note that in the declaration of temporary
variables care was taken to make the variables themselves big enough to
contain their corresponding fields. If the size of an ALPHA temporary
variable is not specified its default size is sixteen bytes.
OLAF is sensitive to techniques that improve efficiency. In the above
duplicate check the SORT's reply says that the key is 52 characters
long and that the total contents of the sort fill three partitions.
This means that there is three times more data being pushed around than
can fit into OLAF's main memory. In a duplicate check it is important
to put the data into some kind of order, but the actual order does not
matter, whether ascending, descending, or something else. Coded fields
do, in fact, offer alternative ordering possibilities. Here is another
sorting possibility for the duplicate check.
*select if 1=1
675 Records Selected
*dec a hold_p<30>, hold_co<20> ;
*sort p^code^; co^code^
Sorting 675 Records. Key is 8 bytes. 1 partitions.
*p/noc/if p = hold_p and co = hold_co then {p;co;//}; &
.. hold_p = p; hold_co = co
CREDENZA OAK
In a test of the two sorts, the first took 3 minutes and 17 seconds,
the second took 1 minute and 30 seconds.
There is a third possibility in sorting coded fields. It is to sort on
the basis of the coded value's position in the coded list. This is
achieved as follows.
*select if 1=1
675 Records Selected
*dec i tmp
*sort tmp = p; tmp; tmp = co; tmp
Sorting 675 Records. Key is 24 bytes. 2 partitions.
*dec a hold_p<30>, hold_co<20> ;
*p/noc/if p = hold_p and co = hold_co then {p;co;//}; &
.. hold_p = p; hold_co = co
CREDENZA OAK
This sort is actually slower than the other two, because there is an
additional cost for sorting DOUBLEs, LONGs, FLOATs, and DATEs as
compared to sorting SHORTs, ALPHAs, INTs, UNSIGNEDs. A declared INT is
internally a LONG, and that is how it happens that the above sort works
with LONGs and becomes slower. The sort of the test took 4 minutes and
50 seconds.
Another desirable edit of the freshly entered data is to make sure that
the product color combination is good. In other words, does a record
exist in the inventory file for the product color combination on the
order record? To perform this kind of edit, it must be possible to
bring both the order and the inventory files together. The following
shows how to do it.
*open order.olf, invent.olf
ORDER.OLF Retrieved
INVENT.OLF Rectieved
*dec a hold_p<30>, hold_co<20>
*dec i tmp
*proc check_select 2
CHECK_SELECT:: select/silence, find 1/if p = hold_p and &
.. co = hold_co
*proc check_print 2
CHECK_PRINT:: print/noc/tmp = 1
*select if sd = 0
20 Records Selected
*print/noc/tmp = 0; hold_p = p; hold_co = co; &
.. call check_select ; &
.. call check_print ; &
.. if tmp = 0 then { p; co; // }
CHANDELIER KHAKI
The edit detects that there is no such product as a khaki chandelier.
The edit makes use of the procedure feature of OLAF to access two files
at the same time. A procedure has a name and a number that refers the
procedure to one of the opened files. In the example the procedure
number must be one or two, because only two files are open. OLAF may
open up to five OLAF files in the OPEN command. A procedure contains
any one of the following kinds of commands: SELECT, PRINT, CHANGE,
LET, DELETE, SORT. In the above example two procedures are declared
against the second file. One uses a SELECT and the other uses a PRINT.
A procedure does not execute until it is called. In the above example,
only records with no shipping date (sd = 0) undergo the edit. The
PRINT command loads the temporary variables with values from the
selected records, and performs the calls to the two procedures. The
CHECK_SELECT procedure tries to find a record in the inventory file
that matches the values of the variables, and the CHECK_PRINT command
sets a flag to 1 to signal to the calling PRINT command that the match
was found. The calling PRINT then checks the value of the flag, and
prints out the product name and color when the test is negative.
The above method using procedures is one way to perform the necessary
edit. As stated before, OLAF is flexible. There are often many ways
to do the same thing, and some ways are more efficient than others.
The following is a more efficient way to perform the same edit as
above.
*open ORDER.OLF, INVENT.OLF
*dec a check<1>[3000] = "N"
*fil 2
INVENT.OLF Active
*select 1=1
675 Records Selected
*p/noc/check[p * 50 + co] = "Y"
*fil 1
ORDER.OLF Active
*select if check[p * 50 + co] != "Y"
1 Records Selected
*p p;co
CHANDELIER KHAKI
The above example uses a single large array to tie the files together.
After all, all the edit check needs is some indication that the
combination is valid. This yes/no indication can be indicatee above example uses a single large array to tie the files together.
After all, all the edit check needs is some indication that the
combination is valid. This yes/no indication can be indicated in one
byte. A three thousand cell array is declared, its dimenion derived
from the product of the dimensions of the two coded lists involved in
the combination. The first print command in the above example shows
that the numeric property of a coded field may be used to advantage in
this problem. A proper subscript into the array is the numeric value
of the product times fifty, which is the maximum possible value of the
product field (which we know from looking at the MULT parameter in the
FIELDS display), added to which is the numeric value of the color
field.
OLAF has room for 10,000 characters of array space. The array
declaration of the example uses 3,000 characters.
Here is a sample of unfilled orders. This is how they look after they
are entered and before they undergo the transaction processing steps
which seek to fill the orders.
*s if sd = 0
20 Records Selected
*p c; if co != " " then co^v^; p^v^; |40; q; od; qs; sd
1 BEIGE ARM CHAIR 1 14NOV85 0 0
1 BLACK AQUARIUM STAND 1 14NOV85 0 0
1 BUTCHER BLOCK DESK 1 14NOV85 0 0
1 CHANDELIER 1 14NOV85 0 0
2 YELLOW PLASTIC CAFETERIA TABLE 1 14NOV85 0 0
2 WHITE FORMICA CONFERENCE TABLE 1 14NOV85 0 0
3 BLACK HIGH BOOK SHELVES 2 14NOV85 0 0
3 BLACK LOW BOOK SHELVES 1 14NOV85 0 0
3 PINE BENT WOOD CHAIR 3 14NOV85 0 0
3 WOOD COFFEE TABLE 1 14NOV85 0 0
3 MARBLE PEN HOLDER 1 14NOV85 0 0
4 LIGHT WALNUT CREDENZA 1 14NOV85 0 0
4 LOW GLASS TABLE 1 14NOV85 0 0
4 PINE BENT WOOD CHAIR 2 14NOV85 0 0
5 WHITE DIRECTOR'S CHAIR 3 14NOV85 0 0
6 GLOBE 1 14NOV85 0 0
100 BEIGE PARTITION CORNER SECITON 1 14NOV85 0 0
100 BEIGE PARTITION SECTION: 4' x 4' 3 14NOV85 0 0
150 DARK WALNUT CREDENZA 1 14NOV85 0 0
200 BLACK SWIVEL CHAIR 1 14NOV85 0 0
The following is the heart of the order entry system. In the steps
below, for every order line item the correct inventory record is
reduced, and the order item record itself is updated to show that it is
filled if and only if there is sufficient inventory to cover it. Order
items for which there is not sufficient inventory simply remain
unchanged.
*open order.olf,invent.olf
ORDER.OLF Retrieved
INVENT.OLF Retrieved
*dec a hold_p<30>, hold_co<20> ;
*dec date_today = 11nov85 ;
*dec i qty_wanted, tmp
*proc inventory_check 2
INVENTORY_CHECK:: change/find 1,nowrite, silence/ &
.. if product = hold_p and color = hold_co &
.. and q >= qty_wanted then &
.. { q = q - qty_wanted; tmp = 1 }
*change if sd = 0 then { hold_p = product ; &
.. hold_co = color; qty_wanted = quantity ; &
.. tmp = 0 ; call inventory_check; &
.. if tmp = 1 then {sd = today; qs = quantity}; }
19 Records Changed
The above sequence of commands makes use of a procedure, whose change
command has three options. The first option, "FIND 1", improves
efficiency because it tells OLAF to stop searching the file after
finding the first match. The second option, "NOWRITE", has effect if
and only if a CHANGE command is used within a procedure. Normally a
CHANGE command writes to the file after it has found all its matches.
The "NOWRITE" option directs the CHANGE to suspend its writes until the
completion of the calling command. The "SILENCE" option tells the
CHANGE to not report its results after its execution, which would occur
every time it is called.
Here is how the orders look after attempt to fill them.
*s if od = 14nov85
20 Records Selected
*p c; if co != " " then co^v^; p^v^; |40; q; od; qs; sd
1 BEIGE ARM CHAIR 1 14NOV85 1 14NOV85
1 BLACK AQUARIUM STAND 1 14NOV85 1 14NOV85
1 BUTCHER BLOCK DESK 1 14NOV85 1 14NOV85
1 CHANDELIER 1 14NOV85 1 14NOV85
2 YELLOW PLASTIC CAFETERIA TABLE 1 14NOV85 1 14NOV85
2 WHITE FORMICA CONFERENCE TABLE 1 14NOV85 0 0
3 BLACK HIGH BOOK SHELVES 2 14NOV85 2 14NOV85
3 BLACK LOW BOOK SHELVES 1 14NOV85 1 14NOV85
3 PINE BENT WOOD CHAIR 3 14NOV85 3 14NOV85
3 WOOD COFFEE TABLE 1 14NOV85 1 14NOV85
3 MARBLE PEN HOLDER 1 14NOV85 1 14NOV85
4 LIGHT WALNUT CREDENZA 1 14NOV85 1 14NOV85
4 LOW GLASS TABLE 1 14NOV85 1 14NOV85
4 PINE BENT WOOD CHAIR 2 14NOV85 2 14NOV85
5 WHITE DIRECTOR'S CHAIR 3 14NOV85 3 14NOV85
6 GLOBE 1 14NOV85 1 14NOV85
100 BEIGE PARTITION CORNER SECITON 1 14NOV85 1 14NOV85
100 BEIGE PARTITION SECTION: 4' x 4' 3 14NOV85 3 14NOV85
150 DARK WALNUT CREDENZA 1 14NOV85 1 14NOV85
200 BLACK SWIVEL CHAIR 1 14NOV85 1 14NOV85
One of them is not filled. Probing the inventory file reveals the
reason. The stock of white formica conference tables is completely
gone.
*s if q = 0
1 Records Selected
*p TITION CORNER SECITON 1 14NOV85 1 14NOV85
100 BEIGE PARTITION SECTION: 4' x 4' 3 14NOV85 3 14NOV85
150 DARK WALNUT CREDENZA 1 14NOV85 1 14NOV85
200 BLACK SWIVEL CHAIR 1 14NOV85 1 14NOV85
One of them is not filled. Probing the inventory file reveals the
reason. The stock of white formica conference tables is completely
gone.
*s if q = 0
1 Records Selected
*p co; p
WHITE FORMICA CONFERENCE TABLE
Te next example is much the same, but in this case order items are
filled on a first in first out basis.
*open order.olf,invent.olf,order.olf
ORDER.OLF Retrieved
INVENT.OLF Retrieved
ORDER.OLF Retrieved
*dec a hold_p<30>, hold_co<20>;
*dec date today = 11nov85 ;
*dec i qty_wanted, hold_customer ;
*proc update_order 3
UPDATE_ORDER:: change/find 1, nowrite, silence/
.. if product = hold_p &
.. and color = hold_co &
.. and customer = hold_customer and qs = 0 then &
.. { qs = qty_wanted ; ship_date = today }
*proc inventory_check 2
INVENTORY_CHECK:: change/find 1,nowrite, silence/ &
.. if product = hold_p &
.. and color = hold_co &
.. and q >= qty_wanted then &
.. { q = q - qty_wanted; call update_order }
*select if ship_date = 0
20 Records Selected
*sort order_date
Sorting 20 Records. Key is 6 bytes. 1 Partitions.
*print/noc/ hold_customer = customer ; hold_p = product ; &
.. hold_co = color; qty_wanted = quantity ; &
.. call inventory_check
*
The order file is opened twice in the above command sequence. This is
permissible as long as the updating happens through only one channel to
the file as long as it is open. In the example, ORDER.OLF is both file
1 and file 3. File 3 is the one that is updated. File 1 must never be
updated. In fact, immediately following the final step above it would
be a good practice to give another OPEN command. This would protect
the changes made to ORDER.OLF.
D. Scheduling Programs and a Gantt Chart
-------------------------------------
Features covered:
Date Arithmetic
Date Modifiers
Alpha Arithmetic
OLAF's date arithmetic feature can be used in coordination with its
transaction processing ability as the foundation for a scheduling
system. Such a system might begin with a file defined as follows:
SCHEDULE.OLF
6,100,15,0
ALPHA5,ACTIVITY:A
ALPHA30,DESCRIPTION:DES:D
SHORT/MIN 0 MAX 255/,TIME:T
SHORT/MIN 0 MAX 255/,PRIORITY:P
DATE,START:S
DATE,END:E
In this demonstration, the records of the file describe activities in
the construction of a house. The records are captured with their start
and dates set to 0.
*s 1=1
15 Records Selected
p a; description; time; priority
A1 DIG HOLE 10 0
A2 FORM FOOTINGS 5 10
A3 POUR FOOTINGS 1 20
A4 FORM FOUNDATION WALLS 10 30
A5 BRACE FOUNDATION WALLS 2 40
A6 POUR FOUNDATION WALLS 1 50
A7 FRAME WALLS 10 60
A8 FRAME ROOF 7 70
A9 DO FLOORING 2 60
A10 EXTERIOR WALLS 7 70
A11 CEILINGS 5 70
A12 DRY WALL 5 70
A13 ROOFING 1 80
A14 PAINT 5 90
A15 MOVE IN 3 100
The starting date of the project is declared in a variable named
"today". In this schedule, it is assumed that activities must not
overlap.
*o schedule.olf, schedule.olf
SCHEDULE.OLF Retrieved
SCHEDULE.OLF Retrieved
*dec date today = 14nov85
*dec a hold_a
*proc update 2
UPDATE:: change/find 1, silence, nowrite/ &
..if a = hold_a then {s = today; today = today + t; e = today}
*s 1=1
15 Records Selected
*sort p
Sorting 15 Records. Key is 3 bytes. 1 partitions.
*print/noc/hold_a = a; call update
Here is the result of the above scheduling sequence. Note that an
activity begins when its predecessor ends. The priority field
establishes the ordering of the activities. Note that the report shows
a print modifier that can be used with dates.
*sort s
Sorting 15 Records. Key is 13 bytes. 1 partitions.
*p a; d; t; p; s^mm/dd/yy^; e^mm/dd/yy^
A1 DIG HOLE 10 0 14NOV1985 24NOV1985
A2 FORM FOOTINGS 5 10 24NOV1985 29NOV1985
A3 POUR FOOTINGS 1 20 29NOV1985 30NOV1985
A4 FORM FOUNDATION WALLS 10 30 30NOV1985 10DEC1985
A5 BRACE FOUNDATION WALLS 2 40 10DEC1985 12DEC1985
A6 POUR FOUNDATION WALLS 1 50 12DEC1985 13DEC1985
A7 FRAME WALLS 10 60 13DEC1985 23DEC1985
A8 FRAME ROOF 7 70 25DEC1985 1JAN1986
A9 DO FLOORING 2 60 23DEC1985 25DEC1985
A10 EXTERIOR WALLS 7 70 1JAN1986 8JAN1986
A11 CEILINGS 5 70 8JAN1986 13JAN1986
A12 DRY WALL 5 70 13JAN1986 18JAN1986
A13 ROOFING 1 80 18JAN1986 19JAN1986
A14 PAINT 5 90 19JAN1986 24JAN1986
A15 MOVE IN 3 100 24JAN1986 27JAN1986
Perhaps it is an unreasonable restriction that activities be strictly
sequential. The following command sequence allows acitivities of the
same priority to be worked on concurrently.
*o schedule.olf, schedule.olf
SCHEDULE.OLF Retrieved
SCHEDULE.OLF Retrieved
*dec date today = 14nov85, max_date
*dec i last_p = -1
*dec a hold_a
*proc update 2
UPDATE:: change/find 1, nowrite/if a = hold_a then &
.. { s = today; e = s + t; &
.. if e > max_date then { max_date = e } ; } ;
*s 1=1
15 Records Selected
*sort p
Sorting 15 Records. Key is 3 bytes. 1 partitions.
*prin/noc/ if p != last_p and max_date != 0 then &
.. today = max_date; hold_a = a; call update; last_p = p
The following report shows the results. Note the new date modifier for
the popular mm/dd/yy date format.
*sort s; e
Sorting 15 Records. Key is 24 bytes. 1 partitions.
*p a; d; t; p; s^mm/dd/yy^; e^mm/dd/yy^
A1 DIG HOLE 10 0 11/14/85 11/24/85
A2 FORM FOOTINGS 5 10 11/24/85 11/29/85
A3 POUR FOOTINGS 1 20 11/29/85 11/30/85
A4 FORM FOUNDATION WALLS 10 30 11/30/85 12/10/85
A5 BRACE FOUNDATION WALLS 2 40 12/10/85 12/12/85
A6 POUR FOUNDATION WALLS 1 50 12/12/85 12/13/85
A7 FRAME WALLS 10 60 12/13/85 12/23/85
A8 FRAME ROOF 7 70 12/23/85 12/30/85
A9 DO FLOORING 2 60 12/13/85 12/15/85
A10 EXTERIOR WALLS 7 70 12/23/85 12/30/85
A11 CEILINGS 5 70 12/23/85 12/28/85
A12 DRY WALL 5 70 12/23/85 12/28/85
A13 ROOFING 1 80 12/30/85 12/31/85
A14 PAINT 5 90 12/31/85 1/05/86
A15 MOVE IN 3 100 1/05/86 1/08/86
It's always good to have a picture in a project management system. The
following command sequence shows how to produce a Gantt chart. Some
extra effort was put into it to keep it narrow enough to fit within the
margins of this document. It makes use of alpha arithmetic. An
important rule in alpha arithmetic is that expressions must be kept
very simple when alpha fields and literals are combined with nonalphas.
This means that there can be only one nonalpha in the expression.
Including more than one nonalpha confuses the compiler. To work within
the restricition, put the results of numeric or date expressions into
temporary variables.
*dec i tmp, len
*print tmp = s - 14nov85; len = e - s; &
.. if tmp > 30 then &
.. {d; |30; tmp = tmp - 30; [] * tmp ; "x" * len} &
.. else &
.. { [] * tmp; "x" * len; |45; d}
xxxxxxxxxx DIG HOLE
xxxxx FORM FOOTINGS
x POUR FOOTINGS
xxxxxxxxxx FORM FOUNDATION WALLS
xx BRACE FOUNDATION WALLS
x POUR FOUNDATION WALLS
xx DO FLOORING
xxxxxxxxxx FRAME WALLS
CEILINGS xxxxx
DRY WALL xxxxx
FRAME ROOF xxxxxxx
EXTERIOR WALLS xxxxxxx
ROOFING x
PAINT xxxxx
MOVE IN xxx
E. Sorting Totals
--------------
Feature covered:
Calling procs out of SORT
Sort has more flexibility than the prior examples have shown. It can
call procedures and use IF's, ELSE's, literal fields, and WHILE's.
This sectio will develop the idea of using procedures to solve the
commonly encountered data processing need to sort on a value that no
data base records contain.
The problem to solve is to sort the states of the U.S. and the
provinces of CANADA in order of the number of major league baseball
teams that they contain, showing the state with the most first. There
are two files. The first contains a record for each team. The second
contains a single record for each state that contains a team.
Respectively, the two file definitions are:
TEAMS.OLF
3,100,27,1
CODE/MULT 50 CODE 2 PNAME 16/ "AL"="ALABAMA" "AK"="ALASKA" &
"AR"="ARKANSAS" "AZ"="ARIZONA" "CA"="CALIFORNIA" "CN"="CONNECTICUT" &
"DE"="DELAWARE" "GA"="GEORGIA" "ID"="IDAHO" "IA"="IOWA" "IL"= &
"ILLNOIS" "IN"="INDIANA" "KY"="KENTUCKY" "LA"="LOUISIANA" "MA"= &
"MASSACHUSETTS" "MD"="MARYLAND" "ME"="MAINE" "MI"="MICHIGAN" &
"MN"="MINNESOTA" "MO"="MISSOURI" "NE"="NEBRASKA" "NH"="NEW HAMPSHIRE" &
"NM"="NEW MEXICO" "NV"="NEVADA" "NY"="NEW YORK" "NC"="NORTH CAROLINA" &
"ND"="NORTH DAKOTA" "OH"="OHIO" "OK"="OKLAHOMA" "ON"="ONTARIO" &
"OR"="OREGON" "PA"="PENNSYLVANIA" "QU"="QUEBEC" "RI"="RHODE ISLAND" &
"SC"="SOUTH CAROLINA" "SD"="SOUTH DAKOTA" "TN"="TENNESSEE" "TX"= &
"TEXAS" "UT"="UTAH" "VI"="VIRGINIA" "VT"="VERMONT" "WA"="WASHINGTON" &
"WV"="WEST VIRGINIA" "WI"="WISCONSIN" "WY"="WYOMING",STATE:STA &
:ST:S
ALPHA20,CITY:C
ALPHA20,TEAM:T
STATE.OLF
1,60,16,0
CODE/MULT 50 CODE 2 PNAME 16/ "AL"="ALABAMA" "AK"="ALASKA" &
.
. (states are as shown in TEAMS.OLF)
.
"WI"="WISCONSIN" "WY"="WYOMING",STATE:STA:ST:S
The following command sequence shows how SORT, using CALLS to select
the teams and count them, can fabricate a key which it can then employ.
The key appears with a modifier to indicate that the key should be
sorted in descending order.
*open state.olf, teams.olf
STATE.OLF Retrieved
TEAMS.OLF Retrieved
*dec a hold
*dec i team_cnt = 0
*proc sel 2
SEL::select/silence/if hold = state
*proc pri 2
PRI::print/noc/team_cnt = team_cnt + 1
*select 1=1
16 Records Selected
*sort hold = state; call sel; team_cnt=0; call pri; team_cnt^des^
Sorting 16 Records. Key is 13 bytes. 1 partitions.
*heading "State"; |30; "Nbr Teams"; //; &
"-----"; |30; "---------"
*print hold = state; call sel; team_cnt = 0; call pri; state; &
..|24; team_cnt
State Nbr Teams
----- ---------
CALIFORNIA 5
ILLNOIS 2
MISSOURI 2
NEW YORK 2
OHIO 2
PENNSYLVANIA 2
TEXAS 2
GEORGIA 1
MARYLAND 1
MASSACHUSETTS 1
MICHIGAN 1
MINNESOTA 1
ONTARIO 1
QUEBEC 1
WASHINGTON 1
WISCONSIN 1
A variation of the above command sequence makes it possible to
see the teams that belong to each state.
*open state.olf, teams.olf
*dec a hold
*dec i team_cnt = 0
*proc sortsel 2
SORTSEL::select/silence/if hold = state
*proc sortprint 2
SORTPRINT::print/noc/team_cnt = team_cnt + 1
*select 1=1
16 Records Selected
*sort hold = state; call sortsel; team_cnt = 0; call sortprint; &
..team_cnt^des^
Sorting 16 Records. Key is 13 bytes. 1 partitions.
*heading "State"; |30; "Nbr Teams"; //; &
"-----"; |30; "---------"
*proc showteams 2
SHOWTEAMS::print |15; team
*print hold = state; call sortsel; team_cnt = 0; call sortprint; &
..state; |24; team_cnt; //; call showteams
State Nbr Teams
----- ---------
CALIFORNIA 5
A'S
ANGELS
DODGERS
GIANTS
PADRES
ILLNOIS 2
CUBS
WHITE SOX
MISSOURI 2
CARDINALS
ROYALS
NEW YORK 2
METS
YANKEES
OHIO 2
INDIANS
REDS
PENNSYLVANIA 2
PHILLIES
PIRATES
TEXAS 2
RANGERS
ASTROS
GEORGIA 1
BRAVES
MARYLAND 1
ORIOLES
MASSACHUSETTS 1
RED SOX
MICHIGAN 1
TIGERS
MINNESOTA 1
TWINS
ONTARIO 1
BLUE JAYS
QUEBEC 1
EXPOS
WASHINGTON 1
MARINERS
WISCONSIN 1
BREWERS
V. Disclaimer
The Author will not be liable to you for any damages, including lost
profits, lost savings, or other incidental or consequential damages
arising out of the use of or the inability to use these programs, event
if the Author has been advised of the possibility of such damages, or
for any claim by any other party.